﻿using Cofe.Core.Property;
using Cofe.Core.Validater;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;

namespace Cofe.Core.Security
{    
    public class GenericPermissionPolicy : IPermissionPolicy<IPropertyHost>//, IXmlSerializable        
    {
        #region Constructor

        private void constructPatterns(string[] matchPatterns)
        {
            _patterns = from str in matchPatterns
                        select new Regex(str,
#if !NETFX_CORE
 RegexOptions.Compiled |
#endif
 RegexOptions.IgnoreCase);            
        }


        public GenericPermissionPolicy(string[] requireRole, object property,
            string[] matchPatterns,
            PermissionType permission = PermissionType.All)
        {
            if (PropertyTypeExtension.GetDefaultPropertyType(property) != typeof(string))
                throw new NotSupportedException(String.Format("{0} is not a string property", property));

            _property = property;
            _permission = permission;
            _matchPatterns = matchPatterns;
            constructPatterns(_matchPatterns);
            RequiredRole = requireRole ?? new string[] {};
        }

        public GenericPermissionPolicy()
        {

        }

        #endregion

        #region Methods

        private bool matchProperty(IPropertyHost requestedObj)
        {
            if (!(requestedObj.Behaviors.IsPropertySupported(_property)))
                return false;

            string value =
                requestedObj.Behaviors.GetPropertyAsync(_property).Result.ValueAsString;

            foreach (var p in _patterns)
                if (p.IsMatch(value))
                    return true;

            return false;
        }

        public bool Match(IPropertyHost requestedObj, PermissionType permissionType)
        {
            return _permission.HasFlag(permissionType) && matchProperty(requestedObj);
        }

        public System.Xml.Schema.XmlSchema GetSchema()
        {
            throw new NotImplementedException();
        }

        private void readMatchPatterns(System.Xml.XmlReader reader)
        {
            List<string> matchPatternList = new List<string>();
            while (reader.Read())
            {
                if (reader.NodeType == XmlNodeType.Element &&
                    reader.Name == "Pattern")
                    matchPatternList.Add(reader.ReadElementContentAsString());
            }
            _matchPatterns = matchPatternList.ToArray();
            constructPatterns(_matchPatterns);
        }

        //public void ReadXml(System.Xml.XmlReader reader)
        //{
        //    reader.MoveToContent();            

        //    reader.MoveToContent();
        //    RequiredRole = reader.GetAttribute("RequiredRole").Split(',');
            
        //    reader.ReadStartElement("MatchPatterns");
        //    readMatchPatterns(reader.ReadSubtree());
        //    reader.ReadEndElement();

        //    _permission = (PermissionType)Int32.Parse(reader.GetAttribute("Permission"));
        //    _property = Int32.Parse(reader.GetAttribute("Property"));
        //}

        //public void WriteXml(System.Xml.XmlWriter writer)
        //{
        //    writer.WriteAttributeString("RequiredRole", String.Join(",", RequiredRole));

        //    writer.WriteStartElement("MatchPatterns");
        //    foreach (var pattern in _matchPatterns)
        //        writer.WriteElementString("Pattern", pattern);
        //    writer.WriteEndElement();

        //    writer.WriteAttributeString("Permission", ((int)_permission).ToString());
        //    writer.WriteAttributeString("Property", ((int)_property).ToString());
        //}

        #endregion

        #region Data

        IEnumerable<Regex> _patterns;
        string[] _matchPatterns;
        PermissionType _permission;
        object _property;


        #endregion

        #region Public Properties


        public string[] RequiredRole { get; private set; }


        #endregion





    }
}
